\documentclass[english,11pt,notitlepage]{article}
\usepackage[T1]{fontenc}
\usepackage[latin1]{inputenc}
\usepackage{amsmath}
\usepackage{babel}

\usepackage[a4paper,headheight=16pt,scale={0.8,0.8},hoffset=0cm]{geometry}

\newcommand{\noun}[1]{\textsc{#1}}

\newenvironment{codecomment}
% {\begin{list}{}{\leftmargin0.5cm\rightmargin0.5cm}\item{}\begin{footnotesize}}
{\begin{list}{}{\leftmargin0cm\rightmargin0cm}\item{}\begin{small}}
{\end{small}\end{list}}

\title{Wiki-Lyrics HOW-TO}

\begin{document}

\maketitle

\section{Introduction}

\subsection{What is Wiki-Lyrics?}

\noindent It's an Amarok lyrics script. However, it has some features that makes it ``special'':

\begin{itemize}
\item It can get lyrics (and suggestions) from \emph{a lot of sites}.
\item It can be easily extended to support other sites.
\item It automatically searches suggestions for the requested lyrics.
\item It can upload lyrics, cover art and album data to Lyriki and/or LyricWiki (wiki's for lyrics).
\end{itemize}

\subsection{How does it works}

\noindent Wiki-Lyrics itself has a sort of plugin system: in the main script's directory there are some Ruby files named \texttt{lyrics\_*.rb}, each one defining a plugin (a special Ruby class) that can get the lyrics from \emph{one site}. The main script calls them when it needs to fetch lyrics and/or suggestions.

\section{The plugins}

\subsection{Writing a plugin}

\noindent First few lines are ``standard'':

\begin{verbatim}
$LOAD_PATH << File.expand_path(File.dirname(__FILE__))
require 'utils/strings'
require 'lyrics'
\end{verbatim}

\noindent This is to import some classes and modules we'll have to use.

\noindent Now we can create our class, let's call it FooLyrics:

\begin{verbatim}
class FooLyrics < Lyrics
\end{verbatim}

\noindent First two methods provide basic information about the site and are self explanatory:

\begin{verbatim}
def FooLyrics.site_host()
    return 'www.lyrics.foo.bar'
end

def FooLyrics.site_name()
    return 'Foo'
end
\end{verbatim}

\noindent OK, that was easy. We just created 2 class-methods that return the URL and the name of the site we are getting the lyrics from. Now, let's write some real code. Though the \texttt{Lyrics} class can be extended in several ways, in the most common scenario (and the one we'll explain here), there are 4 additional methods our class should implement:

\begin{verbatim}
def build_lyrics_fetch_data( artist, title, album=nil, year=nil )
    a = CGI.escape( artist )
    t = CGI.escape( title )
    return { 'url'=>"http://#{site_host()}/index.php?a=#{a}&t=#{t}.html" }
end
\end{verbatim}
\begin{codecomment}
The method receives song information and must return a hash with at least one key, \texttt{'url'}, and optionally another one, \texttt{'post'}. As the method name suggests, the data returned by this method will be used to fetch the lyrics page for the song in question, with the \texttt{'url'} key being the URL of the page to retrieve. Normally the page will be retrieved through a \texttt{GET} request but if some parameters need to be posted to the site in order to get the lyrics, you can provide them with the optional key \texttt{'post'}, which expects a hash. When \texttt{'post'} is specified, the page will be retrieved through a \texttt{POST} request and the data provided will be sent to the site (note that \texttt{GET} parameters are specified as part of the URL).
\end{codecomment}

\hskip

\begin{verbatim}
def parse_lyrics( url, body, artist, title, album=nil, year=nil )
    lyrics_data = {}
    # isolate the lyrics in the received page body
    ...
    lyrics_data['lyrics'] = body
    return lyrics_data
end
\end{verbatim}
\begin{codecomment}
The method receives the fetched page and it's URL and the information received by \texttt{build\_lyrics\_fetch\_data}. It also has to return a hash with at least one key, \texttt{'lyrics'}, and other optional keys: \texttt{'artist'}, \texttt{'title'}, \texttt{'album'}, \texttt{'year'} and \texttt{'custom\_data'}. If the page contains the lyrics to the requested song, they must be returned in the \texttt{'lyrics'} key as plain text (not html, though you can leave formatting tags such as \texttt{<b>}, \texttt{<i>} or \texttt{<u>}); otherwise the \texttt{'lyrics'} key should be set to \texttt{nil}.
You might wonder why return any of the optional keys that are already provided as arguments. The reason is that Wiki-Lyrics does not only retrieves lyrics but can also submit song information to Lyriki and LyricWiki. Instead of only providing the lyrics to the song, Wiki-Lyrics tries to provide those sites with as much (relevant) information as possible. To account for the fact that some information can be missing from the files metadata (or just be inaccurate), all plugins should try to obtain as much information as possible from the lyrics page. The keys that are expected along the lyrics for every plugin (\texttt{'artist'}, \texttt{'title'}, \texttt{'album'} and \texttt{'year'}) will be automatically filled with the values provided to the method if not filled by the plugin (so don't bother filling them unless the data is obtained from the page itself). Any other information available can be returned in the \texttt{'custom\_data'} key, which must contain yet another hash. For example both, Lyriki and LyricWiki plugins return song credits and lyricist this way (as \texttt{'credits'} and \texttt{'lyricist'} keys respectively).
\end{codecomment}

\hskip

\begin{verbatim}
def build_suggestions_fetch_data( artist, title, album=nil, year=nil )
    a = CGI.escape( artist )
    return { 'url'=>"http://#{site_host()}/index.php?search=#{a}.html" }
end
\end{verbatim}
\begin{codecomment}
This method is similar to \texttt{build\_lyrics\_fetch\_data} but, instead of the URL of the lyrics page, it must return the URL where suggestions for the given song can be found (same things noted before for the \texttt{'post'} key apply here).
\end{codecomment}

\hskip

\begin{verbatim}
def parse_suggestions( url, body, artist, title, album=nil, year=nil )
    suggestions = []
    # isolate the suggestions in the received page body
    body.split( /separator regexp/ ) # split the suggestions in the body
        # analyze the suggestion and extract it's url, artist and title
        suggestions << { 'url'=> s_url, 'artist'=>s_artist, 'title'=>s_title }
    end
    return suggestions
end
\end{verbatim}
\begin{codecomment}
As the name suggests, this method must parse the suggestions found in the received page body and return them as an array of hashes (one hash per suggestion), each hash containing \texttt{'url'}, \texttt{'artist'} and \texttt{'title'} keys.
\end{codecomment}

\subsubsection{Useful functions}

\noindent Wiki-Lyrics includes some functions to help you in some ``standard'' operations. Some of those are listed below\footnote{For other commonly used functions take a look at the Ruby modules in the \texttt{utils} directory.}:

\begin{itemize}
\item \texttt{Strings.latin12utf8(text)} convert text from latin1 to utf-8
\item \texttt{Strings.utf82latin1(text)} convert text from utf-8 to latin1
\item \texttt{build\_google\_feeling\_lucky\_url(artist, title)} returns the URL of the ``feeling lucky'' google search
\end{itemize}

\subsection{Save and install the plugin}
To have Wiki-Lyrics automatically detect plugins, these have to be saved under the script's main directory following the \texttt{lyrics\_PLUGINCLASSNAME.rb} filename convention (\emph{mandatory}, otherwise the plugin won't be loaded).

\noindent Countinuing our example, we would have to save our plugin as \texttt{lyrics\_FooLyrics.rb} under Wiki-Lyrics main directory, usually \texttt{\$HOME/.kde/share/apps/amarok/scripts/wiki\_lyrics}.

\section{Enjoy}

\noindent Now open Amarok, start Wiki-Lyrics script and configure it to use your new plugin.

\noindent And, of course, sing along ;-)


\end{document}
